home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Alles Voor Internet / Tout Pour Internet
/
alles voor internet.iso
/
MacInternet™
/
Telnet
/
NCSA
/
tn3270 2.3d26 source
/
tn3270
/
telnet.c
< prev
next >
Wrap
Text File
|
1991-06-02
|
22KB
|
886 lines
/*
* tn3270 for the Macintosh Source Code
* Brown University Computing and Information Services
* Version 2.3d21, January 17, 1991
* Copyright (c) 1988, 1989, 1990, 1991 by Brown University and by
* Peter John DiCamillo.
*
* Permission is granted to any individual or institution to use, copy,
* or redistribute the binary version of this software and its
* documentation provided this notice and the copyright notices are
* retained. Permission is granted to any individual or non-profit
* institution to use, copy, modify, or redistribute the source files
* of this software provided this notice and the copyright notices are
* retained. This software may not be distributed for profit, either
* in original form or in derivative works, nor can the source be
* distributed to other than an individual or a non-profit institution.
* Any individual or group interested in seeing and/or using these
* source files but who are prevented from doing so by the above
* constraints should contact Don Wolfe, Assistant Vice-President for
* Computer Systems at Brown University, (401) 863-7250, for possible
* software licensing of the source developed at Brown.
*
* Brown University and Peter John DiCamillo make no representations
* about the suitability of this software for any purpose.
*
* BROWN UNIVERSITY AND PETER JOHN DICAMILLO GIVE NO WARRANTY, EITHER
* EXPRESS OR IMPLIED, FOR THE PROGRAM AND/OR DOCUMENTATION PROVIDED,
* INCLUDING, WITHOUT LIMITATION, WARRANTY OF MERCHANTABILITY AND
* WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE.
* -----------------------------------------------------------------------
* The following copyright notice applies to the code in this file for
* interpreting the Telnet protocol and performing option negotiations:
* -----------------------------------------------------------------------
* Copyright (c) 1984-1987 by the Regents of the
* University of California and by Gregory Glenn Minshall.
*
* Permission to use, copy, modify, and distribute these
* programs and their documentation for any purpose and
* without fee is hereby granted, provided that this
* copyright and permission appear on all copies and
* supporting documentation, the name of the Regents of
* the University of California not be used in advertising
* or publicity pertaining to distribution of the programs
* without specific prior permission, and notice be given in
* supporting documentation that copying and distribution is
* by permission of the Regents of the University of California
* and by Gregory Glenn Minshall. Neither the Regents of the
* University of California nor Gregory Glenn Minshall make
* representations about the suitability of this software
* for any purpose. It is provided "as is" without
* express or implied warranty.
*/
#define __SEG__ 3270tcp
#include "maclib.h"
#include "termdef.h"
#include "globals.h"
#define TELCMDS 1
#define TELOPTS 1
#include "telnet.h"
/*
* Telnet receiver states for fsm
*/
#define TS_DATA 0
#define TS_IAC 1
#define TS_WILL 2
#define TS_WONT 3
#define TS_DO 4
#define TS_DONT 5
/* #define TS_CR 6 currently not used */
#define TS_SB 7 /* sub-option collection */
#define TS_SE 8 /* looking for sub-option end */
short telrcv_state; /* FSA state */
char data_init; /* flag for start of new write */
short askedSGA; /* we have talked about SGA */
char sent3270tt; /* flag for sent 3270 type */
char hadascii; /* flag for have had ascii data */
extern char newserver; /* server which supports new protocol */
extern unsigned char tcphostname[]; /* cshostname, or prompt response */
extern char servermode; /* for non-terminal server */
char hisopts[256];
char myopts[256];
static char doopt[] = { IAC, DO, '%', 'c', 0 };
static char dont[] = { IAC, DONT, '%', 'c', 0 };
static char will[] = { IAC, WILL, '%', 'c', 0 };
static char wont[] = { IAC, WONT, '%', 'c', 0 };
static char subbuffer[100],
*subpointer, *subend; /* buffer for sub-options */
#define SB_CLEAR() subpointer = subbuffer;
#define SB_TERM() subend = subpointer;
#define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof(subbuffer))) { \
*subpointer++ = (c); \
}
static char sb_terminal[] = { IAC, SB,
TELOPT_TTYPE, TELQUAL_IS,
'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
IAC, SE };
static char sb_e_terminal[] = { IAC, SB,
TELOPT_TTYPE, TELQUAL_IS,
'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
'-', 'E',
IAC, SE };
#define SBTERMTYPE 11
#define SBTERMMODEL 13
static unsigned char showmsg[80];
static char replybuff[100], *replyptr;
static char quitflg = 0;
extern int myport; /* port for netwrite */
extern char logon;
extern char pend_conn;
extern unsigned char * wsfbuff;
extern char skiplf, escmode;
extern char tcpinv; /* tcp pending invldscr */
telrcv(sbp, scc)
register unsigned char *sbp;
register short scc;
{
register unsigned char c;
register unsigned char *Sbp;
register short Scc;
short endflg, rc, skipcnt;
if (scc <= 0) return;
if (cs.dblevel > 2) tcpdump("telrcv", sbp, scc);
replyptr = replybuff;
while (scc > 0) {
/* if (cs.dblevel > 2) {
sprintf(showmsg, "scc = %d", scc);
putln(showmsg);
} */
c = *sbp++;
scc--;
switch (telrcv_state) {
case TS_DATA:
if (c == IAC) {
telrcv_state = TS_IAC;
continue;
}
Sbp = sbp;
Scc = scc;
skipcnt = 0;
while (Scc > 0) {
c = *Sbp++;
Scc--;
if (c == IAC) {
skipcnt++;
telrcv_state = TS_IAC;
break;
}
}
endflg = 0;
if ((telrcv_state == TS_IAC) && (Scc > 0))
if ((*Sbp) == EOR) {
skipcnt++;
endflg = 1;
Sbp++;
Scc--;
telrcv_state = TS_DATA;
}
tcpdata(sbp-1, scc+1-Scc-skipcnt, data_init, endflg);
data_init = endflg;
sbp = Sbp;
scc = Scc;
break;
case TS_IAC:
switch (c) {
case WILL:
telrcv_state = TS_WILL;
continue;
case WONT:
telrcv_state = TS_WONT;
continue;
case DO:
telrcv_state = TS_DO;
continue;
case DONT:
telrcv_state = TS_DONT;
continue;
case DM:
/*
* We may have missed an urgent notification,
* so make sure we flush whatever is in the
* buffer currently.
*/
/* SYNCHing = 1;
ttyflush();
SYNCHing = stilloob(net);
settimer(gotDM); */
break;
case NOP:
case GA:
break;
case SB:
SB_CLEAR();
telrcv_state = TS_SB;
continue;
case EOR:
tcpdata(0L, 0, data_init, 1);
data_init = 1;
break;
case IAC:
tcpdata(sbp-1, 1, data_init, 0);
data_init = 0;
break;
default:
break;
}
telrcv_state = TS_DATA;
continue;
case TS_WILL:
printoption(">RCVD", will, c, !hisopts[c]);
/* if (c == TELOPT_TM) {
if (flushout) {
flushout = 0;
}
}
else */ if (!hisopts[c]) {
willoption(c, 1);
}
SetIn3270();
telrcv_state = TS_DATA;
continue;
case TS_WONT:
printoption(">RCVD", wont, c, hisopts[c]);
/* if (c == TELOPT_TM) {
if (flushout) {
flushout = 0;
}
}
else */ if (hisopts[c]) {
wontoption(c, 1);
}
SetIn3270();
telrcv_state = TS_DATA;
continue;
case TS_DO:
printoption(">RCVD", doopt, c, !myopts[c]);
if (!myopts[c])
dooption(c);
SetIn3270();
telrcv_state = TS_DATA;
continue;
case TS_DONT:
printoption(">RCVD", dont, c, myopts[c]);
if (myopts[c]) {
myopts[c] = 0;
sprintf(replyptr, wont, c);
replyptr += sizeof (wont) - 2;
/* flushline = 1; */
/* setconnmode(); set new tty mode (maybe) */
printoption(">SENT", wont, c, 0);
}
SetIn3270();
telrcv_state = TS_DATA;
continue;
case TS_SB:
if (c == IAC) {
telrcv_state = TS_SE;
}
else {
SB_ACCUM(c);
}
continue;
case TS_SE:
if (c != SE) {
if (c != IAC) {
SB_ACCUM(IAC);
}
SB_ACCUM(c);
telrcv_state = TS_SB;
}
else {
SB_TERM();
suboption(); /* handle sub-option */
SetIn3270();
telrcv_state = TS_DATA;
}
continue;
default:
break;
}
}
if (quitflg) {
quitflg = 0;
return;
}
if (replyptr != replybuff) {
tcpwrite(replybuff, replyptr-replybuff);
/* sends data, or ends connection if unable to send */
}
}
/*VARARGS*/
printoption(direction, fmt, option, what)
char *direction, *fmt;
short option, what;
{
if (!cs.dblevel) return;
sprintf(showmsg, "%s ", direction+1);
putln(showmsg);
if (fmt == doopt)
fmt = "do";
else if (fmt == dont)
fmt = "dont";
else if (fmt == will)
fmt = "will";
else if (fmt == wont)
fmt = "wont";
else
fmt = "???";
if (option < (sizeof(telopts)/sizeof( telopts[0])))
sprintf(showmsg, "%s %s", fmt, telopts[option]);
else
sprintf(showmsg, "%s %d", fmt, option);
putln(showmsg);
if (*direction == '<') {
putln("\n");
return;
}
sprintf(showmsg, " (%s)\n", what ? "reply" : "don't reply");
putln(showmsg);
}
willoption(option, reply)
short option, reply;
{
char *fmt;
switch (option) {
case TELOPT_ECHO:
/*
* The following is a pain in the rear-end.
* Various IBM servers (some versions of Wiscnet,
* possibly Fibronics/Spartacus, and who knows who
* else) will NOT allow us to send "DO SGA" too early
* in the setup proceedings. On the other hand,
* 4.2 servers (telnetd) won't set SGA correctly.
* So, we are stuck. Empirically (but, based on
* a VERY small sample), the IBM servers don't send
* out anything about ECHO, so we postpone our sending
* "DO SGA" until we see "WILL ECHO" (which 4.2 servers
* DO send).
*/
{
if (askedSGA == 0) {
askedSGA = 1;
if (!hisopts[TELOPT_SGA]) {
willoption(TELOPT_SGA, 0);
}
}
}
/* Fall through */
case TELOPT_EOR:
case TELOPT_BINARY:
case TELOPT_SGA:
case TELOPT_3270:
/* settimer(modenegotiated); */
hisopts[option] = 1;
fmt = doopt;
/* setconnmode(); possibly set new tty mode */
break;
case TELOPT_TM:
return; /* Never reply to TM will's/wont's */
default:
fmt = dont;
break;
}
sprintf(replyptr, fmt, option);
replyptr += sizeof (dont) - 2;
if (reply)
printoption(">SENT", fmt, option, reply);
else
printoption("<SENT", fmt, option, reply);
}
wontoption(option, reply)
short option, reply;
{
char *fmt;
switch (option) {
case TELOPT_BINARY: /* added for Mac tn3270 */
case TELOPT_ECHO:
case TELOPT_SGA:
case TELOPT_3270:
/* settimer(modenegotiated); */
hisopts[option] = 0;
fmt = dont;
/* setconnmode(); Set new tty mode */
break;
case TELOPT_TM:
return; /* Never reply to TM will's/wont's */
default:
fmt = dont;
}
sprintf(replyptr, fmt, option);
replyptr += sizeof (doopt) - 2;
if (reply)
printoption(">SENT", fmt, option, reply);
else
printoption("<SENT", fmt, option, reply);
}
dooption(option)
short option;
{
char *fmt;
switch (option) {
case TELOPT_TM:
fmt = will;
break;
case TELOPT_EOR:
case TELOPT_BINARY:
case TELOPT_TTYPE: /* terminal type option */
case TELOPT_SGA: /* no big deal */
case TELOPT_3270: /* what we're here for */
fmt = will;
myopts[option] = 1;
break;
case TELOPT_ECHO: /* We're never going to echo... */
default:
fmt = wont;
break;
}
sprintf(replyptr, fmt, option);
replyptr += sizeof (doopt) - 2;
printoption(">SENT", fmt, option, 0);
}
/*
* suboption()
*
* Look at the sub-option buffer, and try to be helpful to the other
* side.
*
* Currently we recognize:
*
* Terminal type, send request.
*/
suboption()
{
char * usertype;
short usersize;
unsigned char getmodel();
char sess_ext3270;
if (apiopen) {
sess_ext3270 = (apiopenreq.nowsf == 0);
}
else {
sess_ext3270 = cs.ext3270;
}
printsub("<", subbuffer, subend-subbuffer+1);
switch (subbuffer[0]&0xff) {
case TELOPT_TTYPE:
if ((subbuffer[1]&0xff) == TELQUAL_SEND) {
/* check for a specific type the user specified after
the host name. */
usertype = tcphostname;
while ((*usertype != '\0') && (*usertype != ':')) usertype++;
if (*usertype == ':') {
usertype++;
usersize = 0;
while ((usertype[usersize] != '\0') &&
(usertype[usersize] != ':')) usersize++;
if (usersize > 0) {
movmem(sb_terminal, replyptr, 4);
movmem(usertype, replyptr+4, usersize);
movmem(sb_terminal+14, replyptr+4+usersize, 2);
printsub(">", replyptr+2, 4+usersize);
replyptr += usersize + 6;
if (strncmp(usertype, "IBM-327", 7) == 0)
sent3270tt = 1;
return;
}
}
/*
* Try to send a 3270 type terminal name. Decide which one based
* on the format of our screen, color capabilities, whether
* we should support extended data streams, and whether we are
* sending the first or a subsequent terminal name.
*/
/* Use 3278 unless color is available.
With color, use 3279 unless extended datastream support
is not wanted (sess_ext3270 = 0) and we already tried sending
3279 previously (sent3270tt = 1) */
if (colormac && !((!sess_ext3270) && sent3270tt)) {
sb_terminal[SBTERMTYPE] = '9';
sb_e_terminal[SBTERMTYPE] = '9';
}
else {
sb_terminal[SBTERMTYPE] = '8';
sb_e_terminal[SBTERMTYPE] = '8';
}
/* set model number */
sb_terminal[SBTERMMODEL] =
getmodel(ses_altrows, ses_altcols) & 0x0f;
sb_terminal[SBTERMMODEL] += 0x30;
sb_e_terminal[SBTERMMODEL] = sb_terminal[SBTERMMODEL];
/* For model 4 and 5, always use 3278, since there are no
real 3279-4 and 3279-5 terminals. The VM logical device
facility rejects 3279-4 and 3279-5, even though VM TCP/IP
accepts them (yes, it's a bug). */
if ((sb_terminal[SBTERMMODEL] == '4') ||
(sb_terminal[SBTERMMODEL] == '5')) {
sb_e_terminal[SBTERMTYPE] = sb_terminal[SBTERMTYPE] ='8';
}
/* Append "-E" to terminal type unless extended datastream
support is not wanted (sess_ext3270 = 0) or a previous
terminal type ending with "-E" was possibly rejected
(sent3270tt = 1). */
if (sess_ext3270 && (!sent3270tt)) {
movmem(sb_e_terminal, replyptr, sizeof(sb_e_terminal));
printsub(">", replyptr+2, sizeof(sb_e_terminal)-2);
replyptr += sizeof(sb_e_terminal);
}
else {
movmem(sb_terminal, replyptr, sizeof(sb_terminal));
printsub(">", replyptr+2, sizeof(sb_terminal)-2);
replyptr += sizeof(sb_terminal);
}
sent3270tt = 1;
return;
}
default:
break;
}
}
SetIn3270()
{
GrafPtr gp;
char do3270;
data_init = 1; /* reset data flag after negotiation */
if (!newserver) {
newserver = (myopts[TELOPT_3270] != 0) ||
(hisopts[TELOPT_3270] != 0);
}
if (newserver) {
do3270 = (myopts[TELOPT_3270] /* && hisopts[TELOPT_3270] */);
}
else {
do3270 = (sent3270tt && myopts[TELOPT_BINARY]
&& hisopts[TELOPT_BINARY] /* && !donebinarytoggle */);
}
if (do3270) {
if (!logon) {
EnableItem(myMenus[4], 0); /* enable fkey menu */
DrawMenuBar();
pend_conn = 0;
logon = 1;
newstat();
}
}
else {
if (logon) {
hadascii = 1;
pend_conn = 3;
logon = 0;
skiplf = escmode = 0;
DisableItem(myMenus[4], 0);
DrawMenuBar();
kblock = aplmode = insmode = 0;
fixbracket = cs.std_brack && (!aplmode) && (stdfont != ALAFONT);
kblcode = 0;
tcpinv = 0;
newstat();
clrscn();
invldscr();
}
}
}
printsub(direction, pointer, length)
char *direction, /* "<" or ">" */
*pointer; /* where suboption data sits */
short length; /* length of suboption data */
{
if (cs.dblevel) {
sprintf(showmsg, "%s suboption ",
(direction[0] == '<')? "Received":"Sent");
putln(showmsg);
switch (pointer[0]) {
case TELOPT_TTYPE:
sprintf(showmsg, "Terminal type ");
putln(showmsg);
switch (pointer[1]) {
case TELQUAL_IS:
{
char tmpbuf[sizeof(subbuffer)];
short minlen;
if (length > 3) length -= 3;
if (length < sizeof(tmpbuf)) minlen = length;
else minlen = sizeof(tmpbuf);
movmem(pointer+2, tmpbuf, minlen);
tmpbuf[minlen-1] = 0;
sprintf(showmsg, "is %s.\n", tmpbuf);
putln(showmsg);
}
break;
case TELQUAL_SEND:
sprintf(showmsg, "- request to send.\n");
putln(showmsg);
break;
default:
sprintf(showmsg,
"- unknown qualifier %d (0x%x).\n", pointer[1]);
putln(showmsg);
}
break;
default:
sprintf(showmsg, "Unknown option %d (0x%x)\n",
pointer[0], pointer[0]);
putln(showmsg);
}
}
}
tcpdata(sptr, slen, init, end)
unsigned char * sptr;
short slen;
char init, end;
{
static char wsfflag;
static unsigned char * wsfptr;
static short wsfleft;
short wsflen;
static short xtralen, xtrainit;
static char xtradata[64];
unsigned char * dataptr;
short datalen;
static unsigned char lstopcd;
static unsigned char wsfop;
static char needtoend;
char dbstr[64];
char winit;
if (cs.dblevel > 2) {
sprintf(dbstr, "tcpdata: len = %d, init = %d, end = %d",
slen, init, end);
putln(dbstr);
}
if (apiopenpend) {
apiregister(1); /* register session */
if (!logon) {
apiopenresp(openLineMode);
}
else {
apiopenresp(open3270Mode);
}
}
if (!logon) {
if (kblock) {
kblock = 0;
newstat();
}
hadascii = 1;
if (servermode) putsrv(sptr, slen, 0);
else putscr(sptr, slen, 0);
writeresponse(0);
return;
}
/* length 0 valid only if init==0 and end==1 */
if ((slen == 0) && (init || (!end))) return;
if (init) {
wsfflag = ((sptr[0] == 0x11) || (sptr[0] == 0xf3));
if (wsfflag) {
wsfptr = wsfbuff;
wsfleft = 8192;
wsfop = sptr[0];
}
}
if (wsfflag) {
/* if ((init) && (end)) {
if (cs.dblevel > 1) tcpdump("writesf", sptr, slen);
writesf(sptr, slen, 1);
writeresponse(wsfop);
return;
} */ /* must copy data for vmxfer compression code */
if (slen > 0) {
if (slen > wsfleft) wsflen = wsfleft;
else wsflen = slen;
movmem(sptr, wsfptr, wsflen);
wsfleft -= wsflen;
wsfptr += wsflen;
}
if (end) {
/* invldscr(); */
if (cs.dblevel > 1) tcpdump("writesf", wsfbuff, wsfptr-wsfbuff);
writesf(wsfbuff, wsfptr-wsfbuff, 1);
writeresponse(wsfop);
}
return;
}
if (init) {
lstopcd = sptr[0];
xtralen = xtrainit = 0;
needtoend = 0;
}
switch (lstopcd) {
case 0x01: /* write */
case 0x05: /* erase/write */
case 0x0d: /* erase/write alt. */
case 0xf1: /* SNA write */
case 0xf5: /* SNA erase/write */
case 0x7e: /* SNA erase/write alt. */
if (init && (slen == 1)) { /* just op-code */
xtralen = 1; /* save op-code until wcc */
xtradata[0] = sptr[0];
xtrainit = 1;
break;
}
if (slen > 0) {
needtoend = 1;
if (xtralen > 0)
movmem(xtradata, sptr-xtralen, xtralen);
ldvoff = 0;
dataptr = sptr-xtralen;
datalen = slen + xtralen;
if (xtrainit) winit = 1;
else winit = init;
if (cs.dblevel > 1) {
sprintf(dbstr, "writetm: init = %d", winit);
tcpdump(dbstr, dataptr, datalen);
}
writetm(dataptr, datalen, winit);
xtralen = datalen - ldvoff;
xtrainit = 0;
if (xtralen == 0) break;
if (xtralen > 64) xtralen = 64;
movmem(dataptr+ldvoff, xtradata, xtralen);
}
break;
case 0x0f: /* erase all unprot. */
case 0x6f: /* SNA erase all unprot. */
if (!init) return;
funckey(10);
rdaid = 60;
writeresponse(lstopcd);
return;
case 0x06: /* read modified */
case 0xf6: /* SNA read modified */
if (!init) return;
rdmcmd(rdaid);
writeresponse(lstopcd);
return;
case 0x6e: /* SNA read modified all */
if (!init) return;
rdmacmd(rdaid);
writeresponse(lstopcd);
return;
case 0x02: /* read buffer */
case 0xf2: /* SNA read buffer */
if (!init) return;
rdbuff();
writeresponse(lstopcd);
return;
default:
return;
}
if (end) {
if (needtoend) {
endwcc(); /* sets pndbeep if beep needed */
writeresponse(lstopcd);
needtoend = 0;
}
tcpinv = 1; /* tcpevent will call invldscr and possibly beep */
}
}
tcpkbin(asc, chr, shift) /* handle new character in line mode */
unsigned char asc, chr, shift;
{
static unsigned char nl[2] = {0x0d, 0x0a};
static unsigned char brk[2] = {0xff, 0xf3};
static unsigned char del[2] = {0xff, 0xf7};
static unsigned char up[2] = {0x1b, 0x41};
static unsigned char down[2] = {0x1b, 0x42};
static unsigned char right[2] = {0x1b, 0x43};
static unsigned char left[2] = {0x1b, 0x44};
static unsigned char pf1[3] = {0x1b, 0x4f, 0x50};
static unsigned char pf2[3] = {0x1b, 0x4f, 0x51};
static unsigned char pf3[3] = {0x1b, 0x4f, 0x52};
static unsigned char pf4[3] = {0x1b, 0x4f, 0x53};
unsigned char c, typ, val;
switch(chr) {
case 190: /* "rub-out" function */
tcpwrite(del, 2);
break;
case 170: /* "clear" function */
tcpwrite(brk, 2);
break;
case 142: /* "enter" function */
tcpwrite(nl, 2);
break;
case 175: /* "left" function */
c = 0x08; /* send normal backspace */
tcpwrite(&c, 1);
break;
case 143: /* "pf1" function */
tcpwrite(pf1, 3);
break;
case 144: /* "pf2" function */
tcpwrite(pf2, 3);
break;
case 145: /* "pf3" function */
tcpwrite(pf3, 3);
break;
case 146: /* "pf4" function */
tcpwrite(pf4, 3);
break;
case 173: /* "up" function */
tcpwrite(up, 2);
break;
case 174: /* "down" function */
tcpwrite(down, 2);
break;
case 184: /* "delete-char" function */
tcpwrite(left, 2);
break;
case 176: /* "right" function */
tcpwrite(right, 2);
break;
default:
if (asc > 127) return;
c = asc;
tcpwrite(&c, 1);
break;
}
}